﻿/// <reference name="MicrosoftAjax.js"/>
/// <reference path="/WebUI/core.debug.js"/>
/// <reference path="/WebUI/DataView/script.debug.js"/>

//GridView用来显示一个表格
//支持显示表头、表尾等
//TODO：
//  1.总是显示表头表尾
//  2.FireFox的MoveRow方法补全

Type.registerNamespace("Doo");

Doo.GridView = function (element) {
    Doo.GridView.initializeBase(this, [element]);
}

Doo.GridView.CreateTpls = function (gridview, fields) {
    ///<summary>从已定义的列中生成模板</summary>
    ///<param name="gridview" type="Doo.GridView">GridView</param>
    ///<param name="fields" type="Array" elementType="Array">预定义的列定义，每个列定义为[headertext,bodytemplate,headerattr,bodycss,footertext]</param>
    var tplHead = new Array();
    var tplRow = new Array();
    var tplCol = new Array();
    var tplFoot = new Array();
    var len = fields == null ? -1 : fields.length;
    if (gridview.get_showRowIndex()) {
        tplHead.push("<th class='rowIndex' style='width:30px;'>{%this.__rowIndex=0?'':''}&nbsp;&nbsp;</th>");
        tplCol.push("<colgroup class='rowIndex'></colgroup>");
        tplRow.push("{%++this.__rowIndex }");
        tplFoot.push("");
    }
    for (var i = 0; i < len; i++) {
        var headerattr = fields[i][2];
        var headertext = fields[i][0];
        var bodycss = fields[i][3];
        var bodytpl = fields[i][1];
        var footer = fields[i][4];
        tplHead.push("<th " + headerattr + " onclick='{$event:__sort}'>");
        tplHead.push(headertext);
        tplHead.push("</th>");
        tplCol.push("<colgroup");
        if (bodycss) tplCol.push(" class='" + bodycss + "'");
        tplCol.push("/>");
        tplRow.push(bodytpl);
        tplFoot.push(footer);
    };
    return {
        'root': '{$pager:RecordCount}<table style="width:100%;border-collapse:collapse;" class="{%this.context.css}">\
        <thead><tr>{[header]#}</tr></thead>' +
        (gridview.get_showfooter() ? '<tfoot>{[footer]#}</tfoot>' : '') +
        '{[colgroup]#}<tbody onmousedown="{$event:__move}">{[#Items?white:emptybody]#}{[row]#Items}</tbody></table>',
        'white': ' ',
        'header': tplHead.join(''),
        'row': '<tr><td>' + tplRow.join('</td><td>') + '</td></tr>',
        'colgroup': tplCol.join(''),
        'footer': '<tr><td>' + tplFoot.join('</td><td>') + '</td></tr>',
        'emptybody': '<tr><td colspan="' + fields.length + '">{[empty]#}</td></tr>'
    };
}

Doo.GridView.prototype = {
    initialize: function () {
        Doo.GridView.callBaseMethod(this, 'initialize');
        // Add custom initialization here
        if (this.columns == null) this.columns = [];
        this._generatetpl();
    },
    dispose: function () {
        //Add custom dispose actions here
        Doo.GridView.callBaseMethod(this, 'dispose');
    },

    _istplgenerated: false,

    _allowSort: true,

    get_allowsort: function () { return this._allowSort; },

    set_allowSort: function (value) {
        this._allowSort = value ? true : false;
    },

    _showfooter: false, //是否显示页脚

    get_showfooter: function (v) {
        return this._showfooter;
    },

    set_showfooter: function (v) {
        this._showfooter = v ? true : false;
        this._istplgenerated = false;
    },

    _showRowIndex: false,

    get_showRowIndex: function () { return this._showRowIndex },

    set_showRowIndex: function (value) {
        if (this._showRowIndex == value) return;
        this._istplgenerated = false;
        this._showRowIndex = value;
    },

    css: '',

    columns: null,
    get_columns: function () {
        ///<summary>获取列定义</summary>
        /// <returns type="Array" elementType="Array">预定义的列定义</returns>
        return this.columns;
    },
    set_columns: function (value) {
        ///<summary>设置列定义</summary>
        /// <param name="value" type="Array" elementType="Array">预定义的列定义，每个列定义为[headertext,bodytemplate,headerattr,bodycss,footertext]</param>
        this.columns = value; this._istplgenerated = false;
    },
    appendColumn: function (headertext, bodytemplate, headerattr, bodycss, footertext) {
        if (!this.columns instanceof Array) {
            this.columns = [];
        }
        this.columns.push([headertext, bodytemplate, headerattr, bodycss, footertext]);
        this._istplgenerated = false;
    },

    get_table: function () {
        ///<summary>获取表格元素</summary>
        return this._element.firstChild;
    },

    get_tbody: function () {
        ///<summary>获取TBody元素</summary>
        return this.get_table().tBodies[0];
    },

    /* 样式设置 */
    get_columnstyle: function (index) {
        ///<summary>获取第index列的样式以供设置</summary>
        ///<param name="index" type="Number">从0开始的序号</param>
        var cols = this.get_tbody().getElementsByTagName("col");
        return cols[index].style;
    },

    emptytpl: '没有数据',

    _generatetpl: function () {
        ///<summary>生成模版</summary>
        var tpls = Doo.GridView.CreateTpls(this, this.columns);
        tpls.empty = this.emptytpl;
        this._templatebinder.set_tpls(tpls);
        this.set_tplevent("__sort", this.sortHandler);
        this.set_tplevent("__move", this.moveHandler);
        this._istplgenerated = true;
    },

    resetRowIndex: function (tbody, start, end) {
        var rows = tbody.rows;
        for (var i = start; i <= end; i++) {
            rows[i].cells[0].innerHTML = i + 1;
        }
    },

    sortHandler: function (sender, args, elem, evt) {
        ///<summary>排序事件处理委托</summary>
        ///<param name="sender" type="Doo.GridView">GridView</param>
        if (!sender._allowSort) return; //elem为th，排序方法就是将tbody中的row重新排序
        var desc = elem['sortdesc'] == true;
        elem['sortdesc'] = !desc;
        var cellIndex = elem.cellIndex;
        var table = elem.offsetParent;
        var tbody = table.tBodies[0];
        var rows = tbody.rows;
        var sortArray = new Array();
        for (var i = 0; i < rows.length; i++) {
            var cell = rows[i].cells[cellIndex];
            var valueForSort = cell.innerText || cell.textContent;
            var numberValue = parseFloat(valueForSort);
            sortArray.push([rows[i], valueForSort, numberValue]);
        }
        sortArray.sort(function (a, b) {
            var result;
            if (!isNaN(a[2]) && !isNaN(b[2])) result = a[2] - b[2];
            else result = a[1] > b[1] ? 1 : a[1] == b[1] ? 0 : -1;
            return desc ? -result : result;
        });
        for (var i = sortArray.length - 1; i >= 0; i--) {
            tbody.moveRow(sortArray[i][0].sectionRowIndex, 0);
        }
        if (sender._showRowIndex) sender.resetRowIndex(tbody, 0, rows.length - 1);
    },

    /* 行移动事件处理 */
    _allowMove: false,
    get_allowMove: function () {
        return this._allowMove;
    },
    set_allowMove: function (value) {
        this._allowMove = value;
    },
    dragContext: (function () {
        var cssPreFix = "Doo_GridView_";
        var all = cssPreFix + "Draging";
        var dragRowCss = cssPreFix + "DragRow";
        var handlerRowCss = cssPreFix + "HandlerRow";
        var sourceHandlerRowCss = cssPreFix + "SourceHandlerRow";
        var tableLayoutFixedCss = cssPreFix + "Fixed";
        var styleSetted = false;
        var ensureStyleSet = function () {
            //保证样式表已经设置
            if (styleSetted) return;
            //0.All
            Doo.Css.addCssRule('.' + all, "position:absolute;width:100%;");
            Doo.Css.addCssRule('.' + all + ' td', "border:none");
            //1.DragRow
            Doo.Css.addCssRule('.' + dragRowCss, "border:dotted 2px black;opacity:0.3;");
            //2.HandlerRow
            Doo.Css.addCssRule('.' + handlerRowCss, "border-top:solid 1px blue");
            //3.sourceHandlerRowCss
            Doo.Css.addCssRule('.' + sourceHandlerRowCss, "border:solid 1px red");
            //4.all
            styleSetted = true;
        }
        return {
            initMY: 0,
            initTop: 0,
            maxHeight: 0,
            sourceRow: null,
            dragRow: null,
            handlerRow: null,
            targetRow: null,
            sourceHandlerRow: null,
            ensure: function (tbody) {
                /// <param name="tbody" DomElement="true"></param>
                if (this.dragRow == null) {
                    var row = this.dragRow = tbody.insertRow(-1);
                    var cell = row.insertCell(-1);
                    var cellSpan = tbody.rows[0].cells.length;
                    cell.cellSpan = cellSpan;
                    cell.innerHTML = "<div>&nbsp;</div>";
                    var hrow = this.handlerRow = tbody.insertRow(-1);
                    var hcell = hrow.insertCell(-1);
                    hcell.cellSpan = cellSpan;
                    hcell.innerHTML = "<div>&nbsp;</div>";
                    var shrow = this.sourceHandlerRow = tbody.insertRow(-1);
                    var shcell = shrow.insertCell(-1);
                    shcell.cellSpan = cellSpan;
                    shcell.innerHTML = "<div>&nbsp;</div>";

                    var table = tbody.parentNode;
                    if (table.style.tableLayout.toLowerCase() == "fixed") {
                        Sys.UI.DomElement.addCssClass(tbody, tableLayoutFixedCss);
                    }

                    //设置样式
                    table.style.position = "relative"; //设置table
                    row.className = all + ' ' + dragRowCss;
                    hrow.className = all + ' ' + handlerRowCss;
                    shrow.className = all + ' ' + sourceHandlerRowCss;
                    ensureStyleSet();
                }
                else {
                    tbody.appendChild(this.dragRow);
                    tbody.appendChild(this.handlerRow);
                    tbody.appendChild(this.sourceHandlerRow);
                }
            },
            clear: function () {
                var tbody = this.dragRow.parentNode;
                tbody.removeChild(this.dragRow);
                tbody.removeChild(this.handlerRow);
                tbody.removeChild(this.sourceHandlerRow);
                this.dragRow = null;
                this.handlerRow = null;
                this.sourceHandlerRow = null;
                //释放资源
            }
        }
    })(),
    moveHandler: function (sender, args, tbody, evt) {
        /// <param name="sender" type="Doo.GridView"></param>
        /// <param name="tbody" domElement="true"></param>
        /// <param name="evt" type="Sys.UI.DomEvent"></param>
        var tgt = evt.target;
        var allowMove = this._allowMove;

        //一直上浮到parentNode为elem
        if (tgt == tbody) return;
        evt.stopPropagation();
        var child = tgt;
        while (tgt && tgt.parentNode != tbody) {
            child = tgt;
            tgt = tgt.parentNode;
            if (!allowMove) {
                if (tgt.getAttribute("moveHandler") == "yes") allowMove = true;
            }
        }
        //找到了
        if (!tgt) return;
        if (!allowMove) {
            //查看列定义是否允许移动
            var i = child.cellIndex;
            if (sender._element.firstChild.tHead.rows[0].cells[i].getAttribute("moveHandler") != "yes") return;
        };
        sender.dragContext.ensure(tbody);
        var top = tgt.offsetTop + 'px';
        sender.dragContext.initMY = evt.clientY;
        sender.dragContext.initTop = tgt.offsetTop;
        sender.dragContext.sourceRow = tgt;
        sender.dragContext.targetRow = tgt;
        sender.dragContext.maxHeight = tbody.offsetHeight;
        sender.dragContext.dragRow.style.top = top;
        sender.dragContext.dragRow.style.height = tgt.offsetHeight + 'px';
        sender.dragContext.dragRow.style.display = '';
        sender.dragContext.handlerRow.style.display = '';
        sender.dragContext.handlerRow.style.top = top;
        sender.dragContext.sourceHandlerRow.style.top = top;
        $addHandler(document, "mousemove", sender.get_movingHandler(), false);
        $addHandler(document, "mouseup", sender.get_endmoveHandler(), false);
    },
    _moving: null,
    get_movingHandler: function () {
        if (this._moving == null) this._moving = Function.createDelegate(this, this.movingHandler);
        return this._moving;
    },
    movingHandler: function (evt) {//正在移动...
        /// <param name="evt" type="Sys.UI.DomEvent"></param>
        var top = this.dragContext.initTop + evt.clientY - this.dragContext.initMY;
        evt.preventDefault();
        evt.stopPropagation();
        //寻找放置的地点
        if (top < 0) return;
        var tbody = this.dragContext.sourceRow.parentNode;
        var targetRow = tbody.rows[0];
        var len = tbody.rows.length - 3; //要减掉3个帮助row
        var i = 1;
        while (i < len && targetRow.offsetTop < top) {
            targetRow = tbody.rows[i++];
        }
        if (i == len && targetRow.offsetTop < top) {
            targetRow = null;
        }
        if (this.dragContext.targetRow != targetRow) {
            //tbody.moveRow(this.dragContext.handlerRow.sectionRowIndex, targetRow.sectionRowIndex);
            this.dragContext.handlerRow.style.top = (targetRow == null ? tbody.offsetHeight + tbody.rows[len].offsetHeight : targetRow.offsetTop) + 'px';
            this.dragContext.targetRow = targetRow;
        }
        this.dragContext.dragRow.style.top = top + 'px';
    },
    _endmove: null,
    get_endmoveHandler: function () {
        if (this._endmove == null) this._endmove = Function.createDelegate(this, this.endMoveHandler);
        return this._endmove;
    },
    _moveRow: function (section, indexFrom, indexTo) {
        ///<summary>移动行，用于修复bug，避免被移动到下一个section</summary>
        var l = section.rows.length - 1;
        if (indexTo < l) {
            section.moveRow(indexFrom, indexTo);
        }
        else {
            var row = section.rows[indexFrom];
            section.moveRow(indexFrom, indexTo - 1);
            section.moveRow(indexTo, indexTo - 1);
        }
    },
    endMoveHandler: function (evt) {//结束移动事件
        /// <param name="evt" type="Sys.UI.DomEvent"></param>
        $removeHandler(document, "mousemove", this.get_movingHandler());
        $removeHandler(document, "mouseup", this.get_endmoveHandler());
        this.dragContext.clear();
        var tbody = this.dragContext.sourceRow.parentNode;
        var targetRow = this.dragContext.targetRow;
        var targetIndex = targetRow == null ? tbody.rows.length : targetRow.sectionRowIndex;
        var oldIndex = this.dragContext.sourceRow.sectionRowIndex;
        if (targetIndex > oldIndex) targetIndex--;
        if (targetIndex == oldIndex) return; //目标为本行，即可不移动
        //oldIndex为本行，targetIndex为将要移动到的行
        var args = new Doo.GridViewRowMovingEventArgs(tbody, this.dragContext.sourceRow, targetIndex);
        this.onrowmoving(this, args);
        if (args.cancer == true) {

        }
        else {
            this._moveRow(tbody, oldIndex, targetIndex);
            args = new Doo.GridViewRowMovedEventArgs(tbody, this.dragContext.sourceRow, oldIndex, targetIndex);
            this.onrowmoved(this, args);
            if (this._showRowIndex) {
                if (oldIndex > targetIndex)
                    this.resetRowIndex(tbody, targetIndex, oldIndex);
                else//targetIndex>oldIndex时
                    this.resetRowIndex(tbody, oldIndex, targetIndex);
            }
        }
    },

    //[已重载]
    databind: function (data) {
        if (this._istplgenerated == false) this._generatetpl();
        Doo.GridView.callBaseMethod(this, 'databind', [data]);
    }
}
Doo.Scripts.SetEvents(Doo.GridView.prototype, { 'rowmoving': 0, 'rowmoved': 0 });
Doo.GridView.registerClass('Doo.GridView', Doo.DataViewBase);

Doo.GridViewRowMovingEventArgs = function (tbody, sourceRow, targetIndex) {
    this.sourceRow = sourceRow;
    this.targetIndex = targetIndex;
    this.tbody = tbody;
};
Doo.GridViewRowMovingEventArgs.prototype = {
    sourceRow: null,
    tbody: null,
    targetIndex: 0,
    cancer: false
};
Doo.GridViewRowMovingEventArgs.registerClass("Doo.GridViewRowMovingEventArgs", Sys.EventArgs);

Doo.GridViewRowMovedEventArgs = function (tbody, sourceRow, oldIndex, targetIndex) {
    this.sourceRow = sourceRow;
    this.targetIndex = targetIndex;
    this.tbody = tbody;
    this.oldIndex = oldIndex;
};
Doo.GridViewRowMovedEventArgs.prototype = {
    sourceRow: null,
    tbody: null,
    oldIndex: 0,
    targetIndex: 0
};
Doo.GridViewRowMovedEventArgs.registerClass("Doo.GridViewRowMovedEventArgs", Sys.EventArgs);

/* 一个排序的例子
var setOrder = function (row, i) { row.cells[1].innerHTML = i; };
var getOrder = function (row) { return parseInt(row.cells[1].innerHTML); };
var oldOrder = getOrder(args.sourceRow);
var min = args.oldIndex, max = args.targetIndex;
if (min > max) { var tmp = min; min = max; max = tmp; }
var i = min;
var tbody = args.tbody;
var maxlen = tbody.rows.length;
var order = 1;
if (i > 0) {
//有前一项，进行计算
var po = getOrder(tbody.rows[i - 1]);
order = po + 1; setOrder(tbody.rows[i], order++);
}
else {
setOrder(tbody.rows[0], order++);
}
while (++i < maxlen) {
//依次计算
var oo = getOrder(tbody.rows[i]);
if (oo > order && i > max) break;
setOrder(tbody.rows[i], order++);
} */